package com.adee.netty.mydubbo.client;

import com.adee.netty.mydubbo.HelloService;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;

import java.lang.reflect.Proxy;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MyDubboConsumer {
    // private final ExecutorService es = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
    private final ExecutorService es = Executors.newFixedThreadPool(1);
    private static final ExecutorService es2 = Executors.newFixedThreadPool(1);
    private MyDubboConsumerHandler h;

    public static void main(String[] args) throws InterruptedException {
        MyDubboConsumer m = new MyDubboConsumer();
        es2.execute(() -> {
            m.start("127.0.0.1", 7000);
        });
        //TimeUnit.SECONDS.sleep(15);
        for (int i = 0; i < 10; i++) {
            HelloService s = m.getProxy(HelloService.class);
            System.out.println(s.hello("Rose" + i));
        }
    }

    // 创建一个target对象的代理对象，将rpc逻辑编制到目标方法中
    public <T> T getProxy(Class<T> serviceClass) {
        MyDubboConsumer myDubboConsumer = this;
        return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                new Class[]{serviceClass}, (proxy, method, args) -> {
                    synchronized (myDubboConsumer) {
                        while (h == null) myDubboConsumer.wait();
                    }
                    h.setReq(serviceClass.getName() + "#" + method.getName() + "#" + args[0]);
                    String ret = es.submit(h).get();
                    return ret;
                });
    }

    public void start(String host, int port) {
        NioEventLoopGroup group = new NioEventLoopGroup(1);
        try {
            Bootstrap bootstrap = new Bootstrap();
            MyDubboConsumerHandler h = new MyDubboConsumerHandler(this);
            this.h = h;
            bootstrap.group(group).channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline p = ch.pipeline();
                            p.addLast(new StringDecoder());
                            p.addLast(new StringEncoder());
                            p.addLast(h);
                        }
                    });
            ChannelFuture future = bootstrap.connect(host, port).sync(); // 没有.sync()，则不会调用handler.channelActive方法
//            HelloService s = getProxy(HelloService.class);
//            System.out.println(s.hello("Rose"));
            synchronized(this) {
                this.notifyAll();
            }

            future.channel().closeFuture().sync();
        }catch (Exception e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }
    }
}
